package serv

import (
	"d-serv-go/server/core/base"
	"d-serv-go/server/core/bean"
	"d-serv-go/server/core/consts"
	"d-serv-go/server/core/db"
	"d-serv-go/server/core/log"
	"d-serv-go/server/core/util"
	strutils "d-serv-go/server/core/util/stringutils"
	"errors"
	"fmt"
	"strings"
)

type CommServ struct {
}

func (c *CommServ) BeforeSave(bean *db.ParamBean)                         {}
func (c *CommServ) BeforeBatchSave(bean *db.ParamBean)                    {}
func (c *CommServ) BeforeDelete(bean *db.ParamBean)                       {}
func (c *CommServ) BeforeQuery(bean *db.ParamBean)                        {}
func (c *CommServ) BeforeFinds(bean *db.ParamBean)                        {}
func (c *CommServ) BeforeByid(bean *db.ParamBean)                         {}
func (c *CommServ) BeforePrint(bean *db.ParamBean, outBean *bean.OutBean) {}
func (c *CommServ) BeforeStart(bean *db.ParamBean, bean2 bean.Bean)       {}
func (c *CommServ) BeforeFinish(bean *db.ParamBean)                       {}
func (c *CommServ) BeforeExp(bean *db.ParamBean)                          {}
func (c *CommServ) BeforeImp(bean *db.ParamBean)                          {}
func (c *CommServ) BeforeExpZip(bean *db.ParamBean)                       {}
func (c *CommServ) BeforeImpZip(bean *db.ParamBean)                       {}
func (c *CommServ) AfterSave(bean *db.ParamBean, out *bean.OutBean)       {}
func (c *CommServ) AfterBatchSave(bean *db.ParamBean)                     {}
func (c *CommServ) AfterDelete(bean *db.ParamBean)                        {}
func (c *CommServ) AfterQuery(bean *db.ParamBean)                         {}
func (c *CommServ) AfterFinds(bean *db.ParamBean)                         {}
func (c *CommServ) AfterByid(bean *db.ParamBean)                          {}
func (c *CommServ) AfterStart(bean *db.ParamBean)                         {}
func (c *CommServ) AfterFinish(bean *db.ParamBean)                        {}
func (c *CommServ) AfterExp(bean *db.ParamBean)                           {}
func (c *CommServ) StartWf(bean *db.ParamBean)                            {}

func (c *CommServ) Query(paramBean *db.ParamBean) *bean.OutBean {
	context := db.Ctx()
	out := bean.NewOutBean()
	servId := paramBean.GetServId()
	serv, err := ServUtils.GetServBean(servId)
	if err != nil {
		return out.SetError(fmt.Sprintf("获取服务定义异常:{}", servId))
	}
	instance := paramBean.Get(consts.INSTANCE)
	if instance != nil {
		instance.(ServAop).BeforeQuery(paramBean)
	}
	page := paramBean.GetQueryPage()
	rowCount := paramBean.GetShowNum()
	if rowCount > 0 {
		page.SetShowNum(rowCount)
		page.SetNowPage(paramBean.GetNowPage())
	} else {
		if !page.Contains(consts.PAGE_SHOWNUM) {
			if paramBean.GetQueryNoPageFlag() {
				page.SetShowNum(0)
			} else {
				page.SetShowNum(serv.GetPageCount(50))
			}
		}
	}
	sql := strutils.NewStringBuilder("select ")
	cols := bean.NewBean("")
	//在查询语句Select之后加入指定关键字，如：Distinct
	if paramBean.IsNotEmpty(consts.SELECT_KEYWORDS) {
		sql.Append(" ").Append(paramBean.GetStr(consts.SELECT_KEYWORDS)).Append(" ")
	}
	qSelect := paramBean.GetSelect()
	// hideItems := ""
	if len(qSelect) == 0 || qSelect == "*" {
		bListFlag := qSelect == "*"
		items := serv.GetAllItems()
		selects := strutils.NewStringBuilder(serv.GetPKey())
		bKey := true
		for _, key := range items.Keys() {
			item := items.GetBean(key)
			listFlag := item.GetInt("ITEM_LIST_FLAG")
			//主键无论是否列表显示都输出
			if bKey && item.GetStr("ITEM_CODE") == serv.GetPKey() {
				//如果定义为隐藏有数据，则提供给前端时设为不显示
				if listFlag == consts.ITEM_LIST_FLAG_HIDDEN {
					listFlag = consts.ITEM_LIST_FLAG_NO
				}
				AddCols(cols, item, listFlag)
				bKey = false
			} else if listFlag != consts.ITEM_LIST_FLAG_NO || bListFlag {
				if item.GetInt("ITEM_TYPE") == consts.ITEM_TYPE_TABLE || item.GetInt("ITEM_TYPE") == consts.ITEM_TYPE_VIEW {
					selects.Append(",").Append(item.GetStr("ITEM_CODE"))
				}
				if listFlag == consts.ITEM_LIST_FLAG_HIDDEN { //如果定义为隐藏有数据，则提供给前端时设为不显示
					listFlag = consts.ITEM_LIST_FLAG_NO
				}
				AddCols(cols, item, listFlag)
			}
		}
		sql.Append(selects.ToString())
	} else {
		sql.Append(qSelect)
		// hideItems = paramBean.GetQueryHide()
	}
	order := strutils.NewStringBuilder(" order by ")
	servOrder := serv.GetSqlOrder()
	pageOrder := paramBean.GetQueryPageOrder()

	if len(pageOrder) > 0 { //排序设定的优先级：分页排序 > 参数排序 > 服务排序 > 更新时间倒叙
		order.Append(pageOrder)
	} else {
		if paramBean.Contains(consts.PARAM_ORDER) {
			order.Append(paramBean.GetOrder())
		} else if len(servOrder) > 0 { //存在缺省排序设定
			order.Append(servOrder)
		} else { //没有任何排序设定
			order.Clear()
		}
	}
	// 获取操作表或查询表
	tableName := bean.If(paramBean.Contains(consts.PARAM_TABLE), paramBean.GetTable(), serv.GetTableView())
	sql.Append(" from ").Append(tableName.(string))
	fullWhere := getFullWhere(paramBean, serv)
	if strings.Index(strings.ToLower(fullWhere), "and") >= 0 {
		sql.Append(" where").Append(fullWhere[3:])
	}
	if len(paramBean.GetGroupBy()) > 0 {
		sql.Append(" GROUP BY ").Append(paramBean.GetGroupBy())
	}
	sql.Append(order.ToString())
	//
	list, err := context.GetExecutor().QueryPage(sql.ToString(), page.GetNowPage(), page.GetShowNum(), nil, nil)
	if err != nil {
		out.SetError(fmt.Sprintf("err:%v", err))
	}
	out.SetData(list)
	out.SetPage(page)
	out.SetCols(cols)
	log.Info(sql.ToString())
	if instance != nil {
		instance.(ServAop).AfterQuery(paramBean)
	}
	return out
}

func getFullWhere(paramBean *db.ParamBean, serv *ServBean) string {
	where := strutils.NewStringBuilder("")
	if paramBean.IsNotEmpty(consts.PARAM_WHERE) { // 获取ParamBean里的_WHERE_
		where.Append(ServUtils.ReplaceSysVars(paramBean.GetStr(consts.PARAM_WHERE)))
	}
	if paramBean.IsNotEmpty("_linkWhere") { // 有linkwhere则服务设定的过滤就不起作用，除非设置了忽略
		where.Append(ServUtils.ReplaceSysVars(paramBean.GetStr("_linkWhere")))
		if paramBean.GetInt("_linkServQuery") == consts.YES_INT { //关联中启用了服务过滤规则
			where.Append(serv.GetServDefWhere())
		}
	} else { // 没有linkwhere则以服务设定的过滤为基础
		where.Append(serv.GetServDefWhere())
	}
	if paramBean.IsNotEmpty("_queryId") { // 常用查询
		//Bean queryBean = (Bean) serv.getAllQueries().get(paramBean.GetStr("_queryId"));
		//if (queryBean != null) {
		//	where.append(" ").append(ServUtils.replaceSysVars(queryBean.getStr("QUERY_SQL")));
		//}
	}
	where.Append(" ").Append(ServUtils.ReplaceSysVars(paramBean.GetStr("_extWhere")))
	where.Append(ServUtils.GetSearchWhere(serv, paramBean.GetStr("_searchWhere")))
	if paramBean.Contains("_treeWhere") && paramBean.IsNotEmpty("_treeWhere") {
		// where.Append(ServUtils.GetTreeWhere(serv, (List < Bean >) paramBean.GetStr("_treeWhere")))
	}
	if paramBean.Contains("_dictWhere") && paramBean.IsNotEmpty("_dictWhere") {
		where.Append(paramBean.GetStr("_dictWhere"))
	}
	return strings.Trim(where.ToString(), " ")
}

func AddCols(cols *bean.Bean, itemBean *bean.Bean, listFlag int) {
	colBean := itemBean.CopyOf([]string{"ITEM_CODE", "ITEM_NAME"})
	code := colBean.GetStr("ITEM_CODE")
	if itemBean.IsNotEmpty("DICT_ID") { // 字典项需要单独生成生成一份名称列，用原有的显示标志，编码隐藏
		nameBean := colBean.Clone()
		nameCode := code + "__NAME"
		nameBean.Set("ITEM_CODE", nameCode)
		// 使用原字段定义的是否显示来控制字典项
		nameBean.Set("ITEM_LIST_FLAG", listFlag)
		cols.Set(nameCode, nameBean)
		colBean.Set("ITEM_LIST_FLAG", consts.NO_INT)
	} else { //非字典项采用指定的列表标志
		colBean.Set("ITEM_LIST_FLAG", listFlag)
	}
	cols.Set(code, colBean)
}

func (c *CommServ) Finds(paramBean *db.ParamBean) *bean.OutBean {
	out := bean.NewOutBean()
	instance := paramBean.Get(consts.INSTANCE)
	if instance != nil {
		instance.(ServAop).BeforeFinds(paramBean)
	}
	servId := paramBean.GetServId()
	serv, err := ServUtils.GetServBean(servId)
	if err != nil {
		return out.SetError(fmt.Sprintf("获取服务定义异常:{}", servId))
	}
	if !paramBean.Contains(consts.PARAM_ORDER) { //自动设置order排序，如果没有手工指定则从服务定义获取
		paramBean.SetOrder(serv.GetSqlOrder())
	}

	dataList, err := db.ServDao.Finds(servId, paramBean)
	if err != nil {
		out.SetError(fmt.Sprintf("err:%v", err))
		return out
	}

	out.SetData(dataList).SetCount(len(dataList))
	if instance != nil {
		instance.(ServAop).AfterFinds(paramBean)
	}
	return out
}

// byid,count,save,add,modify,batchSave,delete,imp,exp,expZip,impZip
func (c *CommServ) Save(paramBean *db.ParamBean) *bean.OutBean {
	out := bean.NewOutBean()
	//servId := paramBean.GetServId()
	//serv, _ := ServUtils.GetServBean(servId)
	//传递级联处理参数并执行保存方法
	if len(paramBean.GetId()) == 0 { //如果缺省没有KEY，则为添加模式
		paramBean.SetAddFlag(true)
	}
	if paramBean.GetAddFlag() { //保存强制添加标志或者没有主键，则自动为添加模式
		out = c.Add(paramBean)
	} else {
		out = c.Modify(paramBean)
	}
	//if (serv.getWebSocketSync().equals(Constant.YES)) {
	//	Bean msg = (Bean) outBean.clone();
	//	msg.remove(ParamBean.SAVE_OLD_DATA);
	//	VertxMgr.publishMsg("SY." + servId, new JsonObject((Map)outBean));
	//}
	//if (serv.IsOkOrWarn()) {
	//	serv.setSaveIds(outBean.getId()); //设置成功的ID给消息机制使用
	//	ServUtils.saveIndex(servDef, outBean); //处理全文索引信息
	//}
	//if (serv.isNotEmpty("S_WF_INST")) { //此数据在工作流中
	//	ProcServ procServ = new ProcServ();
	//	procServ.addWfInfoToOut(servId, outBean, paramBean); //进行工作流相关逻辑处理
	//}

	return out
}

func (c *CommServ) Add(paramBean *db.ParamBean) *bean.OutBean {
	context := db.Ctx()
	out := bean.NewOutBean()
	instance := paramBean.Get(consts.INSTANCE)
	// remove掉，不然下面的clone会异常
	paramBean.Remove(consts.INSTANCE)
	//初始化参数，获取数据库原始数据，检查各种规则验证许可========================================
	servId := paramBean.GetServId()
	serv, err := ServUtils.GetServBean(servId)
	if err != nil {
		return out.SetError(fmt.Sprintf("获取服务定义异常:{}", err))
	}
	oldId := paramBean.GetId()
	newId := paramBean.GetStr(serv.GetPKey())
	if len(newId) == 0 { //如果新ID不存在，提前预制ID，确保树形字典等保存前置相关信息处理正确
		newId = util.Lang.GetUUID()
		paramBean.Set(serv.GetPKey(), newId)
	}

	//不再根据_PK_判断是否添加，改为'#_ADD_#'=='true'来判断是否为添加
	checkActExpression(serv, consts.ACT_SAVE, &paramBean.Bean) //执行操作表达式检查
	//前监听========================================
	if instance != nil {
		instance.(ServAop).BeforeSave(paramBean)
	}
	if len(serv.GetDictCodes()) > 0 { //如果树形服务，需要处理树形路径
		beforeAddTreeDictField(serv, &paramBean.Bean)
	}
	dataBean, err := db.ServDao.Create(servId, paramBean)
	if err != nil {
		return out.SetError(fmt.Sprintf("获取服务定义异常:{}", err))
	}
	if dataBean != nil {
		out.SetMap(dataBean.GetMap())
		if oldId != (newId) { //处理主键字段与预制主键不一致的情况
			updateRelatePKey(serv, oldId, newId)
		}
		//处理子功能批量添加，必须运行在级联模式下
		if serv.HasLink() { //执行级联添加
			//进行关联删除的判断
			linksBean := serv.GetAllLinks()
			for _, key := range linksBean.Keys() {
				link := linksBean.GetBean(key)
				if link.GetInt("LINK_READONLY") == consts.YES_INT { //忽略只读关联
					continue
				}

				linkServ := link.GetStr("LINK_SERV_ID")
				if paramBean.Contains(linkServ) { //存在级联添加的数据
					db.NewParamBean()
					linkParam := db.NewParamBean2(linkServ, consts.ACT_BATCHSAVE)
					linkParam.SetBatchSaveDatas(paramBean.GetBeans(linkServ))
					linkParam.Set(consts.IS_LINK_ACT, true) //设定为级联模式
					linkParam.SetAddFlag(true)              //传递添加模式标志
					linkParam.Set("SERV_ID", link.GetStr("LINK_SERV_ID"))
					db.ServMgr.Act(linkParam)
				}
			}
		}
		out.SetOk(context.GetSyMsg("SY_ADD_OK"))
		//执行保存后监听
		if instance != nil {
			//确保添加的后监听在流程启动前完成
			instance.(ServAop).AfterSave(paramBean, out)
		}
		//处理工作流的流程绑定
		//if serv.HasWfAuto() && startWf(servId, outBean) { //启动流程，如果成功重载提示信息（流程会自动设置实体信息）
		//	out.SetOk(context.getSyMsg("SY_WF_START_OK"))
		//} else { //如果没有启动流程，则直接设定标题项，存入实体表
		//	if serv.GetDataTitle().length() > 0 {
		//		EntityMgr.addEntity(servDef, outBean, paramBean)
		//	}
		//}
	} else {
		out.SetError(context.GetSyMsg("SY_ADD_ERROR"))
		//即使错误也执行保存后监听
		if instance != nil {
			//确保添加的后监听在流程启动前完成
			instance.(ServAop).AfterSave(paramBean, out)
		}

	}

	return out
}

func beforeAddTreeDictField(servDef *ServBean, paramBean *bean.Bean) {
	dictId := util.GetFirstBySep(servDef.GetDictCodes(), ",")
	dict := db.DictMgr.GetDict(dictId)
	if db.DictMgr.IsSingleTree(dict) { //独立树形字典
		code := dict.GetStr("DICT_F_ID")
		pCode := dict.GetStr("DICT_F_PARENT")
		codePath := dict.GetStr("DICT_F_PATH")
		level := dict.GetStr("DICT_F_LEVEL")
		if len(codePath) == 0 || len(level) == 0 { //忽略没有设定CODE_PATH和CODE_LEVEL字段的
			return
		}
		if paramBean.IsEmpty(pCode) { //没有选父数据，自身缺省为第一级
			paramBean.Set(level, 1)
			paramBean.Set(codePath, paramBean.GetStr(code)+consts.CODE_PATH_SEPERATOR)
		} else { //选了父数据
			pData, _ := db.ServDao.FindById(servDef.GetId(), paramBean.GetStr(pCode), false)
			if pData != nil {
				paramBean.Set(level, pData.GetInt(level)+1)
				paramBean.Set(codePath, pData.GetStr(codePath)+paramBean.GetStr(code)+consts.CODE_PATH_SEPERATOR)
			}
		}
	}
}

func beforeModifyTreeDictField(servDef *ServBean, paramBean *db.ParamBean) error {
	dictId := util.GetFirstBySep(servDef.GetDictCodes(), ",")
	dict := db.DictMgr.GetDict(dictId)
	if dict != nil && db.DictMgr.IsSingleTree(dict) { //独立树形字典
		pCode := dict.GetStr("DICT_F_PARENT")
		codePath := dict.GetStr("DICT_F_PATH")
		level := dict.GetStr("DICT_F_LEVEL")
		if len(codePath) == 0 || len(level) == 0 { //忽略没有设定CODE_PATH和CODE_LEVEL字段的
			return nil
		}
		if paramBean.Contains(pCode) || paramBean.Contains(servDef.GetPKey()) { //变更了父编码或者编码
			fullData := paramBean.GetSaveFullData()
			pId := fullData.GetStr(pCode)
			id := fullData.GetStr(dict.GetStr("DICT_F_ID"))
			paramBean.Set(servDef.GetPKey(), id) //为级联处理初始化编码参数
			if len(pId) == 0 {                   //没有父，自身为第一级
				paramBean.Set(level, 1)
				paramBean.Set(codePath, id+consts.CODE_PATH_SEPERATOR)
			} else {
				param := db.NewParamBean()
				param.Set(dict.GetStr("DICT_F_ID"), pId)
				pData, _ := db.ServDao.Find1(servDef.GetId(), param)
				if pData != nil {
					if strings.Index(pData.GetStr(codePath), fullData.GetStr(codePath)) >= 0 { //自身的子不能作为父
						return base.NewTipErr(db.Ctx().GetSyMsg("SY_SERV_DICT_PCODE_ERROR"))
					}
					paramBean.Set(level, pData.GetInt(level)+1)
					paramBean.Set(codePath, pData.GetStr(codePath)+id+consts.CODE_PATH_SEPERATOR)
				} else {
					paramBean.Set(level, 1)
					paramBean.Set(codePath, id+consts.CODE_PATH_SEPERATOR)
				}
			}
			recurSubDatas(dict, paramBean)
		}
	}
	return nil
}

func recurSubDatas(dict *bean.Bean, data *db.ParamBean) error {
	servId := data.GetStr(consts.PARAM_SERV_ID)
	code := dict.GetStr("DICT_F_ID")
	pCode := dict.GetStr("DICT_F_PARENT")
	codePath := dict.GetStr("DICT_F_PATH")
	level := dict.GetStr("DICT_F_LEVEL")
	if len(data.GetId()) == 0 { //要求必须有主键数据才进行递归处理
		return nil
	}
	param := db.NewParamBean()
	param.Set(pCode, data.GetId())
	param.Set(consts.PARAM_SELECT, code)
	subList, err := db.ServDao.Finds(servId, param)
	if err != nil {
		return err
	}
	for _, sub := range subList {
		sub.Set(level, data.GetInt(level)+1)
		sub.Set(codePath, data.GetStr(codePath)+sub.GetStr(code)+consts.CODE_PATH_SEPERATOR)
		sub.Set(consts.PARAM_SERV_ID, servId)
		sub.Set(pCode, data.GetStr(code))
		param2 := db.NewParamBean(sub)
		recurSubDatas(dict, param2)
		db.ServDao.Update(servId, param2)
	}
	return nil
}

func updateRelatePKey(serv *ServBean, oldKey string, newKey string) {
	if util.IsEmpty(oldKey) {
		return
	}
	//更新文件主键
	if serv.HasFile() { //包含文件信息
		whereBean := db.NewParamBean()
		whereBean.Set("SERV_ID", serv.GetSrcId())
		whereBean.Set("DATA_ID", oldKey)
		setBean := bean.NewBean("").Set("DATA_ID", newKey)
		db.ServDao.Updates(consts.SY_COMM_FILE, setBean, whereBean)
	}
	//更新相关文件
	//if (serv.HasRelate()) {
	//	RelateMgr.updateRelate(servDef, oldKey, newKey);
	//}
}

func checkActExpression(serv *ServBean, act string, dataBean *bean.Bean) error {
	actBean := serv.GetAct(act)
	if actBean != nil && actBean.IsNotEmpty("ACT_EXPRESSION") { // 设了表达式处理，且没有设定忽略验证
		script := actBean.GetStr("ACT_EXPRESSION")
		pos := strings.Index(script, ";") // 如果存在前后端表达式个性化规则设定，只启用后端规则
		if pos >= 0 {
			script = script[pos+1:]
		}
		if len(script) > 0 {
			script = ServUtils.ReplaceSysAndData(script, dataBean)
			if !util.Lang.IsTrueScript(script) {
				return errors.New("无效的act")
			}
		}
	}
	return nil
}

func (c *CommServ) Modify(paramBean *db.ParamBean) *bean.OutBean {
	out := bean.NewOutBean()
	//初始化参数，获取数据库原始数据，检查各种规则验证许可========================================
	servId := paramBean.GetServId()
	servDef, _ := ServUtils.GetServBean(servId)
	oldBean, err := db.ServDao.FindById(servId, paramBean.GetId(), false)
	if err != nil { //从数据库装载老数据
		return out.SetError(db.Ctx().GetSyMsg("SY_SAVE_NOTEXISTS", paramBean.GetId()))
	}
	checkActExpression(servDef, consts.ACT_SAVE, oldBean) //执行操作表达式检查
	//如果服务定义设定了判断乐观锁，进行更新时间的判断
	if servDef.HasLock() && paramBean.Contains("S_MTIME") {
		if paramBean.GetStr("S_MTIME") != oldBean.GetStr("S_MTIME") { //更新时间不一致
			return out.SetError(db.Ctx().GetSyMsg("SY_SAVE_MTIME_ERROR"))
		}
	}
	paramBean.Set(db.SAVE_OLD_DATA, oldBean)

	instance := paramBean.Get(consts.INSTANCE)
	if instance != nil {
		instance.(ServAop).BeforeSave(paramBean)
	}
	// TODO
	if len(servDef.GetDictCodes()) > 0 { //如果树形服务，需要处理树形路径
		beforeModifyTreeDictField(servDef, paramBean)
	}
	//要返回的最新数据信息
	out.SetMap(oldBean.GetMap())

	okFlag := false     //是否执行成功
	changeFlag := false //判断数据项是否变更
	uniqueFlag := false //是否判断唯一性约束
	changeList := make([]*bean.Bean, 0)
	for _, key := range paramBean.Keys() {
		item := servDef.GetItem(key)
		if item != nil {
			if paramBean.GetStr(key) != oldBean.GetStr(key) {
				if item.GetInt("ITEM_LOG_FLAG") == consts.YES_INT { //处理数据变更留痕
					change := bean.NewBean("")
					change.Set("ITEM_ID", item.GetId()).Set("DATA_ID", oldBean.GetId())
					change.Set("ILOG_OLD", oldBean.Get(key)).Set("ILOG_NEW", paramBean.Get(key))
					change.Set("SERV_ID", servId).Set("ITEM_CODE", item.GetStr("ITEM_CODE"))
					if item.IsNotEmpty("DICT_ID") { //字典处理名称
						oldValue := db.DictMgr.GetFullNames(item.GetStr("DICT_ID"), oldBean.GetStr(key))
						newValue := db.DictMgr.GetFullNames(item.GetStr("DICT_ID"), paramBean.GetStr(key))

						change.Set("ILOG_OLD", oldValue).Set("ILOG_NEW", newValue)
					}
					changeList = append(changeList, change)
				}
				out.Set(key, paramBean.Get(key)) //记录更新的内容到outBean中
				if !changeFlag {
					changeFlag = true
				}
			}
			if item.GetInt("ITEM_UNIQUE_GROUP") > 0 { //变更的字段涉及唯一约束
				uniqueFlag = true
			}
		}
	}
	//数据正式处理========================================
	if changeFlag { //只有修改了才进行保存处理
		//进行组合值的处理
		combineItems := servDef.GetCombineItems()
		for _, item := range combineItems { //处理组合值字段
			itemCode := item.GetStr("ITEM_CODE")
			primaryKey := servDef.GetPKey()
			if itemCode != primaryKey {
				combine := ServUtils.GenCombineItem(servId, itemCode, item.GetStr("ITEM_INPUT_CONFIG"), out)
				if combine != out.GetStr(itemCode) { //组合值发生了变更
					paramBean.Set(itemCode, combine)
					out.Set(itemCode, combine)
				}
			}
		}
		//进行唯一组约束的判断
		if uniqueFlag {
			uniqueStr := ServUtils.CheckUniqueExists(servDef, &out.Bean, false)
			if len(uniqueStr) > 0 {
				return out.SetError(db.Ctx().GetSyMsg("SY_SAVE_UNIQUE_EXISTS", uniqueStr))
			}
		}
		result, err := db.ServDao.Update(servId, paramBean)
		if err != nil {
			return out.SetError(fmt.Sprintf("%v", err))
		}
		if result != nil {
			okFlag = true
			out.Set("S_MTIME", result.Get("S_MTIME")) //传递更新时间
			oldId := paramBean.GetId()
			newId := result.GetStr(servDef.GetPKey())
			if len(newId) == 0 { //新ID如果没有值，说明没有变更主键
				newId = oldId
			}
			//如果设定标题项，且存在变更，存入实体表
			//if len(servDef.GetDataTitle()) > 0 && (paramBean.Contains("S_WF_NODE") || paramBean.Contains("S_EMERGENCY") || BeanUtils.containsValue(servDef.GetDataTitle(), paramBean) || BeanUtils.containsValue(servDef.getDataCode(), paramBean) || newId != oldId)) {
			//	EntityMgr.updateEntity(servDef, outBean, paramBean);
			//}
			if newId != oldId { //主键发生变化，更新相关的附件等
				out.SetId(newId)
				updateRelatePKey(servDef, oldId, newId)
			}
		}
	}
	//关联服务数据处理========================================
	linkMsg := ""
	if servDef.HasLink() { //执行级联修改
		linkOutBean := linkUpdate(servId, oldBean, &paramBean.Bean)
		if linkOutBean.IsOk() {
			if !okFlag {
				okFlag = true
			}
		} else {
			changeFlag = true
			linkMsg = linkOutBean.GetStr(consts.RTN_MSG)
		}
	}
	//执行成功后清除缓存记录历史等
	if okFlag { //保存执行成功
		out.SetOk(db.Ctx().GetSyMsg("SY_SAVE_OK")) //先处理成功标志，后面统一处理文件
		//进行变更历史的记录
		if len(changeList) > 0 {
			ServUtils.ItemLog(changeList)
		}
	} else {
		if changeFlag {
			if len(linkMsg) > 0 {
				out.SetMsg(linkMsg)
			} else {
				out.SetError(db.Ctx().GetSyMsg("SY_SAVE_ERROR"))
			}
		} else {
			out.SetWarn(db.Ctx().GetSyMsg("SY_SAVE_NOCHANGE"))
		}
	}

	if instance != nil {
		instance.(ServAop).AfterSave(paramBean, out)
	}
	return out
}

func linkUpdate(servId string, oldBean *bean.Bean, newBean *bean.Bean) *bean.OutBean {
	outBean := bean.NewOutBean()
	msg := strutils.NewStringBuilder()
	servDef, _ := ServUtils.GetServBean(servId)
	// 进行关联保存的判断
	links := servDef.GetAllLinks()
	for _, key := range links.Keys() {
		link := links.GetBean(key)
		if (link.GetInt("LNKE_READONLY") == consts.YES_INT) || (link.GetInt("LINK_UPDATE_FLAG") != consts.YES_INT) { // 忽略只读关联以及非关联更新设定
			continue
		}
		// 进行批量提交数据的判断，执行批量保存
		linkServ := link.GetStr("LINK_SERV_ID")                      // 批量保存想数据键值
		delsKey := linkServ + "__DELS"                               // delete项数据数据键值
		if newBean.Contains(linkServ) || newBean.Contains(delsKey) { // 存在级联修改的数据
			param := db.NewParamBean2(linkServ, consts.ACT_BATCHSAVE)
			param.SetBatchSaveDatas(newBean.GetBeans(linkServ))
			param.SetBatchSaveDelIds(newBean.GetStr(delsKey))
			param.Set("SERV_ID", link.GetStr("LINK_SERV_ID"))
			param.Set(consts.IS_LINK_ACT, true) // 设定当前处理运行在级联处理模式下
			param.SetLinkFlag(true)             // 设定级联处理标志
			linkOutBean := db.ServMgr.Act(param)
			if !linkOutBean.IsOk() {
				msg.Append(linkOutBean.GetStr(consts.RTN_MSG)).Append(" ")
			}
		} else { // 进行变更项的判断，执行主子保存处理
			setBean := bean.NewBean("")
			whereBean := bean.NewBean("")
			linkItems := link.GetBeans("SY_SERV_LINK_ITEM")
			canUpdate := false
			for _, item := range linkItems {
				if item.GetInt("LINK_VALUE_FLAG") == consts.YES_INT {
					linkServ, err := ServUtils.GetServBean(key)
					if err != nil {
						return outBean.SetError(fmt.Sprintf("%v", err))
					}
					linkItem := linkServ.GetItem(item.GetStr("LINK_ITEM_CODE"))
					if linkItem != nil && linkItem.GetInt("ITEM_TYPE") == consts.ITEM_TYPE_TABLE { // 获取表字段
						if newBean.Contains(item.GetStr("ITEM_CODE")) { // 变更字段涉及传值字段
							canUpdate = true
							setBean.Set(item.GetStr("LINK_ITEM_CODE"), newBean.GetStr(item.GetStr("ITEM_CODE")))
						}
						if item.GetInt("LINK_WHERE_FLAG") == consts.YES_INT { // 过滤条件
							whereBean.Set(item.GetStr("LINK_ITEM_CODE"), oldBean.Get(item.GetStr("ITEM_CODE")))
						}
					}
				} else if item.GetInt("LINK_WHERE_FLAG") == consts.YES_INT { // 固定值过滤条件
					whereBean.Set(item.GetStr("LINK_ITEM_CODE"), item.Get("ITEM_CODE"))
				}
			}
			if whereBean.Size() == 0 { // 没有设置where条件，不允许级联更新
				canUpdate = false
			}
			if canUpdate { // 执行批量更新处理
				db.ServDao.Updates(link.GetStr("LINK_SERV_ID"), setBean, db.NewParamBean(whereBean))
			}
		}
	} //end for
	if msg.Len() > 0 {
		outBean.SetMsg(msg.ToString())
	} else {
		outBean.SetOk("")
	}
	return outBean
}
